import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
const tickInterval = 30;
export function useTransition(options = {}) {
    const duration = computed(() => {
        return options.duration || 0;
    });
    const enterFromClass = computed(() => {
        return options.enterFromClass || `${options.prefix}enter-from`;
    });
    const enterActiveClass = computed(() => {
        return options.enterActiveClass || `${options.prefix}enter-active`;
    });
    const enterToClass = computed(() => {
        return options.enterToClass || `${options.prefix}enter-to`;
    });
    const leaveFromClass = computed(() => {
        return options.leaveFromClass || `${options.prefix}leave-from`;
    });
    const leaveActiveClass = computed(() => {
        return options.leaveActiveClass || `${options.prefix}leave-active`;
    });
    const leaveToClass = computed(() => {
        return options.leaveToClass || `${options.prefix}leave-to`;
    });
    const realVisible = ref(false);
    const transitionClass = ref('');
    let status = '';
    let timer;
    let tickTimer;
    function nextTick(callback) {
        tickTimer = setTimeout(() => {
            tickTimer = null;
            callback();
        }, tickInterval);
    }
    function clearAllTimeout() {
        if (tickTimer) {
            clearTimeout(tickTimer);
            tickTimer = null;
        }
        if (timer) {
            clearTimeout(timer);
            timer = null;
        }
    }
    function callHook(name) {
        options.onVisibleHook?.(name);
    }
    function enter() {
        clearAllTimeout();
        if (status === 'leaving') {
            callHook('leave-cancelled');
        }
        status = 'entering';
        realVisible.value = true;
        transitionClass.value = `${enterFromClass.value} ${enterActiveClass.value}`;
        callHook('before-enter');
        nextTick(() => {
            transitionClass.value = `${enterActiveClass.value} ${enterToClass.value}`;
            callHook('enter');
        });
        timer = setTimeout(() => {
            timer = null;
            if (status === 'entering' && options.visible) {
                entered();
            }
        }, duration.value + tickInterval);
    }
    function entered() {
        clearAllTimeout();
        status = 'entered';
        transitionClass.value = '';
        callHook('after-enter');
    }
    function leave() {
        clearAllTimeout();
        if (status === 'entering') {
            callHook('enter-cancelled');
        }
        status = 'leaving';
        transitionClass.value = `${leaveFromClass.value} ${leaveActiveClass.value}`;
        callHook('before-leave');
        nextTick(() => {
            transitionClass.value = `${leaveActiveClass.value} ${leaveToClass.value}`;
            callHook('leave');
        });
        timer = setTimeout(() => {
            timer = null;
            if (status === 'leaving' && !options.visible) {
                leaved();
            }
        }, duration.value + tickInterval);
    }
    function leaved() {
        clearAllTimeout();
        status = 'leaved';
        transitionClass.value = '';
        realVisible.value = false;
        callHook('after-leave');
    }
    function onTransitionEnd() {
        if (status === 'entering' && options.visible) {
            entered();
        }
        else if (status === 'leaving' && !options.visible) {
            leaved();
        }
    }
    onMounted(() => {
        if (options.visible) {
            enter();
        }
    });
    onUnmounted(() => {
        if (timer) {
            clearTimeout(timer);
            timer = null;
        }
        if (tickTimer) {
            clearTimeout(tickTimer);
            tickTimer = null;
        }
    });
    watch(() => options.visible, () => {
        if (options.visible) {
            enter();
        }
        else {
            leave();
        }
    });
    return {
        onTransitionEnd,
        realVisible,
        transitionClass,
    };
}
